/* $RCSFile: AddonNiceIdentity.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.Security/AddonNiceIdentity.cs $
 * $log$
 * Revision 19 2011/02/22 01:23:08  christian.surieux
 *   V4 Migration 22/2/11
 * Revision 19 2011/02/22 01:22:20  christian.surieux
 *   V4 Migration 22/2/11
 * Revision 6 2010/08/06 19:56:30  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Diagnostics;
using System.Security.Principal;
using System.Security;
using System.Net;
using System.Web;
using System.Web.Security;
using System.Xml;
using System.Text;
using AddonNice.Configuration;
using AddonNice.Settings;
using System.Globalization;


namespace AddonNice.Security
{


	public enum AuthenticationType { Unknown, Forms, Windows };
	
	/// <summary>
	/// User identity,class used in place of Windows Identity or FormIdentity when a user is authenticated
	/// </summary>
	public class AddonNiceIdentity : GenericIdentity
	{
		public const int IdentityVer                =   1;          // current version (for data put in cookies)
		private Guid _ProviderUserKey		        =   Guid.Empty; // local membership db key
		private int _typeCode				        =   -1;			// typeCode associated to _CrmId: systemuser, prospect, contact or account
		// Form: CRM Guid for the entity associated with this user, account, contact or lead, typecode in accordance 
		// AD:   CRM Guid for this user tycode is systemsuer
		private Guid _CrmId				            =   Guid.Empty; 
		
		private string _authenticationType          =	string.Empty;

		#region crm credentials used to connect this user when authentication is Form
		
		private Guid _CrmImpersonateId              =   Guid.Empty; // Crm Id used to impersonate CRM access
		private string _CrmImpersonateDomain		=	string.Empty;
		private string _CrmImpersonateLogin			=	string.Empty; // credentials for this Id
		private string _CrmImpersonatePwd			=	string.Empty;
		
		#endregion crm credentials 

		/// <summary>
		/// Try to extract AddonNiceIdentity from context identity
		/// </summary>
		public static AddonNiceIdentity CurrentIdentity
		{
			get 
			{		
				// User Information
				if ( HttpContext.Current != null && HttpContext.Current.User != null
						&& HttpContext.Current.User is ADNCRMPrincipal)
				{
					return ((ADNCRMPrincipal )HttpContext.Current.User).AddonNiceIdentity;
				}
				if ( SecurityTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]AddonNiceIdentity CurrentIdentity NOT found",SecurityTraceSwitch.Sw.Info);
				return null;
			}
		} 

		/// <summary>
		/// Used to force CrmId and TypeCode when Authentication is Windows AD 
		/// </summary>
		/// <param name="CId"></param>
		/// <param name="tpCode"></param>
		public void SetCrmId(Guid CId,int tpCode)
		{
			_CrmId      =   CId;
			_typeCode   =   tpCode;
		}


		/// <summary>
		/// Used when constructing from a cookie
		/// </summary>
		public AddonNiceIdentity(string username,string userData)
			: base(username,"Forms")
		{
			if ( SecurityTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity Ctor with UserName: {0}, UserData: {1}", username,userData),SecurityTraceSwitch.Sw.Info);
			string[] uData				        =	userData.Split(new char[]{'|'},StringSplitOptions.RemoveEmptyEntries);
			int nbDim					        =	uData.Length;
			if (nbDim < 10)
			{
				MembershipUser usr              =   Membership.GetUser(username);
				userData                        =   usr.Comment;
				if (SecurityTraceSwitch.Sw.TraceVerbose)
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity Ctor creating IIdentity with Membership user: '{0}'",
						usr),SecurityTraceSwitch.Sw.Info);
			}
			SetUserData(userData);
		}

		
		/// <summary>
		/// Used when constructing from an existing CRM user
		/// </summary>
		public AddonNiceIdentity(string name,AuthenticationType autType)
			: base(name,autType.ToString())
		{
			if ( SecurityTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity Ctor with Name: {0}, authenticationType: {1}", name, autType ),SecurityTraceSwitch.Sw.Info);
		}

		/// <summary>
		/// Constructor used in Global.asax when windowsAuthentication is in place (Authentication=Windows in web.config)
		/// </summary>
		public AddonNiceIdentity(IIdentity wId)
			: base(wId.Name,wId.AuthenticationType)
		{
			if ( SecurityTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity Ctor with IIdentity wId.Name: {0}, wId.AuthenticationType: {1}, Identity is: {2}",
					wId.Name,wId.AuthenticationType,wId.GetType()),SecurityTraceSwitch.Sw.Info);
		}


		public AddonNiceIdentity(FormsAuthenticationTicket ticket)
			: base(ticket.Name,"Forms")
		{
			if ( SecurityTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity Ctor with FormsAuthenticationTicket Name: '{0}', ticket.UserData: '{1}'",
					ticket.Name,ticket.UserData),SecurityTraceSwitch.Sw.Info);
			string	userData					=	ticket.UserData;
			SetUserData(userData);
			if ( SecurityTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( "[V]AddonNiceIdentity Ctor with FormsAuthenticationTicket END.",SecurityTraceSwitch.Sw.Info);
		}

		private void SetUserData(string userData)
		{
			if ( SecurityTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity SetUserData BEG userData: '{0}'", userData),SecurityTraceSwitch.Sw.Info);
			string[] uData				=	userData.Split(new char[]{'|'},StringSplitOptions.RemoveEmptyEntries);
			int nbDim					=	uData.GetUpperBound(0)+1;
			if ( SecurityTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity SetUserData nbDim: {0}", nbDim),SecurityTraceSwitch.Sw.Info);
			if (nbDim < 10)
			{
				if ( SecurityTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine("[V]AddonNiceIdentity SetUserData END nbdim < 10.",SecurityTraceSwitch.Sw.Info);
				return;
			}
			try
			{
				int ver = int.Parse(uData[0]);
				if (ver == 1)
				{
					//Name					=	uData[1];
					//AuthenticationType	    =	uData[2];
					if ( SecurityTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity SetUserData CrmId: {0}", uData[3]),SecurityTraceSwitch.Sw.Info);
					_CrmId = new Guid(uData[3]);
					if ( SecurityTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity SetUserData typeCode: {0}", uData[4]),SecurityTraceSwitch.Sw.Info);
					_typeCode = int.Parse(uData[4]);
					if ( SecurityTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity SetUserData _ProviderUserKey: {0}", uData[5]),SecurityTraceSwitch.Sw.Info);
					_ProviderUserKey = new Guid(uData[5]);
					if ( SecurityTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity SetUserData _CrmImpersonateId: {0}", uData[6]),SecurityTraceSwitch.Sw.Info);
					_CrmImpersonateId = new Guid(uData[6]);
					_CrmImpersonateDomain = DecodeSpecialCars(uData[7],false);
					if ( SecurityTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity SetUserData _CrmImpersonateDomain: {0}", _CrmImpersonateDomain),SecurityTraceSwitch.Sw.Info);
					_CrmImpersonateLogin = DecodeSpecialCars(uData[8],false);
					if ( SecurityTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity SetUserData _CrmImpersonateLogin: {0}", _CrmImpersonateLogin),SecurityTraceSwitch.Sw.Info);
					_CrmImpersonatePwd = DecodeSpecialCars(uData[9],true);
				}
			}
			catch (Exception ex)
			{
				if ( SecurityTraceSwitch.Sw.TraceError )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]AddonNiceIdentity SetUserData ex: {0}", ex),SecurityTraceSwitch.Sw.Info);
				throw;
			}

			if ( SecurityTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity SetUserData END this : '{0}'", this),SecurityTraceSwitch.Sw.Info);
		}


		/// <summary>
		/// The typeCode associated with this user, as we may have prospects, contacts and systemusers
		/// </summary>
		public int typeCode
		{
			get
			{
				return _typeCode;
			}
		}

		public Guid CrmId
		{
			get
			{
				return _CrmId;
			}
		}
		
		/// <summary>
		/// The internal user Guid associated with this user in local authentication DB
		/// </summary>
		public Guid ProviderUserKey
		{
			get
			{
				return _ProviderUserKey;
			}
		}
		
		public Guid CrmImpersonateId	
		{
			get { return _CrmImpersonateId; }
			set { _CrmImpersonateId=value; }
		}
		public string CrmImpersonateDomain
		{
			get { return _CrmImpersonateDomain; }
			set { _CrmImpersonateDomain=value; }
		}
		public string CrmImpersonateLogin
		{
			get { return _CrmImpersonateLogin; }
			set { _CrmImpersonateLogin=value; }
		}
		public string CrmImpersonatePwd
		{
			get { return _CrmImpersonatePwd; }
			set { _CrmImpersonatePwd=value; }
		}
			
		/// <summary>
		/// Name | CRMGuid | Authentication
		/// </summary>
		/// <returns></returns>
		public override string ToString()
		{
			return string.Format("{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}|{8}|{9}", new object[] 
							{IdentityVer,Name,AuthenticationType,
							CrmId,typeCode,ProviderUserKey,
							CrmImpersonateId,EncodeSpecialCars(CrmImpersonateDomain,false),EncodeSpecialCars(CrmImpersonateLogin,false),EncodeSpecialCars(CrmImpersonatePwd,true) });
		}

		string EncodeSpecialCars(string str, bool isPwd)
		{
			return Convert.ToBase64String(Encoding.ASCII.GetBytes(str));    
			//return str.Replace("|","\\");
		}


		string DecodeSpecialCars(string str, bool isPwd)
		{
			return Encoding.ASCII.GetString(Convert.FromBase64String(str));
			//return str.Replace("\\","|");
		}
		
		/// <summary>
		/// Default credentials from web.config when user is not a system user
		/// true credentials when systemuser
		/// </summary>
		public ICredentials Credentials
		{
			get
			{
				if ( SecurityTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]AddonNiceIdentity Credentials GET UserName: '{0}': Domain: {1}, Login: {2}, Pwd: {3}", 
						new object[] { Name, CrmImpersonateDomain, CrmImpersonateLogin, CrmImpersonatePwd }),SecurityTraceSwitch.Sw.Info);
				return new NetworkCredential(CrmImpersonateLogin,CrmImpersonatePwd,CrmImpersonateDomain);
			}
		}
		
	}
}